using AutojsController.Helpers;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using System;
using System.Net;
using System.Text.RegularExpressions;

namespace AutojsController.Views;

public partial class IPAddressTextBoxView : UserControl
{
    public IPAddressTextBoxView()
    {
        InitializeComponent();
        this.GetObservable(IPAddressProperty).Subscribe(OnIPAddressChanged);
    }

    public static readonly StyledProperty<string> IPAddressProperty =
            AvaloniaProperty.Register<IPAddressTextBoxView, string>(nameof(IPAddress));

    public string IPAddress
    {
        get => GetValue(IPAddressProperty);
        set => SetValue(IPAddressProperty, value);
    }

    private void OnIPAddressChanged(string newValue)
    {
        var parts = string.IsNullOrEmpty(newValue) ? Array.Empty<string>() : newValue.Split('.');
        if (parts.Length != 4)
        {
            Part1.Text = "";
            Part2.Text = "";
            Part3.Text = "";
            Part4.Text = "";
            return;
        }
        else
        {
            Part1.Text = parts[0];
            Part2.Text = parts[1];
            Part3.Text = parts[2];
            Part4.Text = parts[3];
        }
    }

    private void UpdateIPAddress()
    {
        IPAddress = $"{Part1.Text??"0"}.{Part2.Text??"0"}.{Part3.Text??"0"}.{Part4.Text??"0"}";
    }

    private void TextBox_TextChanged(object? sender, TextChangedEventArgs e)
    {
        if (sender is not TextBox textBox)
            return;
        var text = Regex.Replace(textBox.Text??"", @"[^\d]", "");
        if (int.TryParse(text, out int value) && value > 255)
        {
            value = 255;
            text = "255";
        }
        textBox.Text = text;
        textBox.CaretIndex = text.Length;
        if (text.Length == 3)
        {
            switch(textBox)
            {
                case { Name: "Part1" }:
                    Part2.Focus();
                    Part2.SelectAll();
                    break;
                case { Name: "Part2" }:
                    Part3.Focus();
                    Part3.SelectAll();
                    break;
                case { Name: "Part3" }:
                    Part4.Focus();
                    Part4.SelectAll();
                    break;
                case { Name: "Part4" }:
                    break;
            }
        }
        UpdateIPAddress();
    }

    private void TextBox_GotFocus(object? sender, GotFocusEventArgs e)
    {
        if (sender is TextBox textBox)
        {
            textBox.SelectAll();
        }
    }

    private void TextBox_KeyDown(object? sender, KeyEventArgs e)
    {
        if (sender is not TextBox textBox)
            return;
        switch (e.Key)
        {
            case Key.OemPeriod:
            case Key.Decimal:
            case Key.Space:
            case Key.Enter:
                if (string.IsNullOrEmpty(textBox.Text)) { textBox.Text = "0"; }
                switch (textBox.Name)
                {
                    case "Part1":
                        Part2.Focus();
                        Part2.SelectAll();
                        break;
                    case "Part2":
                        Part3.Focus();
                        Part3.SelectAll();
                        break;
                    case "Part3":
                        Part4.Focus();
                        Part4.SelectAll();
                        break;
                }
                e.Handled = true;
                break;
            case Key.Back:
                switch (textBox.Name)
                {
                    case "Part2" when textBox.SelectionStart == 0:
                        Part1.Focus();
                        Part1.SelectAll();
                        break;
                    case "Part3" when textBox.SelectionStart == 0:
                        Part2.Focus();
                        Part2.SelectAll();
                        break;
                    case "Part4" when textBox.SelectionStart == 0:
                        Part3.Focus();
                        Part3.SelectAll();
                        break;
                }
                e.Handled = true;
                break;
            case Key.Left:
                if (textBox.CaretIndex == 0)
                {
                    switch (textBox.Name)
                    {
                        case "Part2":
                            Part1.Focus();
                            Part1.CaretIndex = Part1.Text?.Length ?? 0;
                            break;
                        case "Part3":
                            Part2.Focus();
                            Part2.CaretIndex = Part2.Text?.Length ?? 0;
                            break;
                        case "Part4":
                            Part3.Focus();
                            Part3.CaretIndex = Part3.Text?.Length ?? 0;
                            break;
                    }
                    e.Handled = true;
                }
                break;
            case Key.Right:
                if (textBox.CaretIndex == textBox.Text?.Length)
                {
                    switch (textBox.Name)
                    {
                        case "Part1":
                            Part2.Focus();
                            Part2.CaretIndex = 0;
                            break;
                        case "Part2":
                            Part3.Focus();
                            Part3.CaretIndex = 0;
                            break;
                        case "Part3":
                            Part4.Focus();
                            Part4.CaretIndex = 0;
                            break;
                    }
                    e.Handled = true;
                }
                break;
        }
    }

    public bool IsValidIPAddress(bool ExceptMask = true)
    {
        if(!System.Net.IPAddress.TryParse(IPAddress, out var address))
            return false;
        if(ExceptMask) return Checks.IsNormalIPAddress(address);
        return true;
    }

    public void Focus(int PartIndex)
    {
        switch (PartIndex)
        {
            case 1:
                Part2.Focus();
                break;
            case 2:
                Part3.Focus();
                break;
            case 3:
                Part4.Focus();
                break;
            default:
                Part1.Focus();
                break;
        }
    }
}